package nio.common;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.util.Iterator;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import nio.entity.Family;
import nio.entity.ResponseMessage;
import nio.entity.User;

public class ServerSocketChannelDemo {
	public static void main(String[] args) {
//		new Thread(new Runnable() {
//			public void run() {
//				createServerChannel(9998);
//			}
//		}).start();
		new Thread(new Runnable() {
			public void run() {
				createServerChannel(9999);
			}
		}).start();
	}

	public static void createServerChannel(int port) {
		try {
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1", port));
			Selector selector = Selector.open();
			serverSocketChannel.configureBlocking(false);
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, 0);
			System.out.println("=====");
			process(selector);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static JSONObject readFromChannel(SocketChannel channel) {
		String result = "";
		try {
			channel.configureBlocking(false);
			ByteBuffer buf = ByteBuffer.allocate(100);
			buf.clear();
			while (true) {
				int readNum = channel.read(buf);
				if (readNum != 0) {
					buf.flip();
					while (buf.hasRemaining()) {
						result += (char) buf.get();
					}
					buf.clear();
				} else {
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(result);
		return JSON.parseObject(result);
	}

	public static void process(Selector selector) {
		try {
			long start = 0l;
			boolean isCheckd = false;
			JSONObject user = null;
			boolean isWrited = false;
			long notReadable = 0l;
			while (true) {
				System.out.println("======selecting======");
				int readyChannels = selector.select();
				System.out.println("readyChannels is:" + readyChannels);
				if (readyChannels == 0) {
					if (isCheckd == false) {
						isCheckd = true;
						start = System.currentTimeMillis();
					} else if (isCheckd == true && System.currentTimeMillis() - start > 2000) {
						selector.close();
						System.out.println("selector is closed!");
						break;
					}
					continue;
				}
				Set<SelectionKey> selectedKeys = selector.selectedKeys();
				System.out.println(selectedKeys.size());
				Iterator<SelectionKey> iterator = selectedKeys.iterator();
				while (iterator.hasNext()) {
					SelectionKey selectionKey = iterator.next();
					int attachment = (int) selectionKey.attachment();
					if (selectionKey.isAcceptable()) {
						// a connection was accepted by a ServerSocketChannel.
						System.out.println("========isAcceptable========");
						ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
						SocketChannel socketChannel = serverSocketChannel.accept();
						socketChannel.configureBlocking(false);
						socketChannel.register(selector, SelectionKey.OP_READ, 1);
						System.out.println("======accepted=======");
					} else if (selectionKey.isConnectable()) {
						// a connection was established with a remote server.

					} else if (selectionKey.isReadable()) {
						System.out.println("=====readable======");
						SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
						user = readFromChannel(socketChannel);
						System.out.println("======writing======");
						if (user != null) {
							ByteBuffer buf = ByteBuffer.allocate(1024);
							buf.clear();
							if ("Tom".equals(user.getString("name"))) {
								pushToBuffer(buf, new Family("Tom", "USA"));
							}
							if ("Liming".equals(user.getString("name"))) {
								pushToBuffer(buf, new Family("Liming", "CHINA"));
							}
							buf.flip();
							socketChannel.write(buf);
							selectionKey.cancel();
						}
						System.out.println("======writing end======");
					} else if (selectionKey.isWritable()) {
						// a channel is ready for writing
						System.out.println("=====writable======");
						SocketChannel channel = (SocketChannel) selectionKey.channel();
					}
					iterator.remove();
				}
			}
			System.out.println("=====iterate end=======");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void pushToBuffer(ByteBuffer buffer, Object responseBody) {
		String responseBodyJString = JSON.toJSONString(responseBody);
		String responseMessageJString = "ML"
				+ (responseBodyJString.length() + 3 + String.valueOf(responseBodyJString.length() + 3).length()) + "#"
				+ responseBodyJString;
		buffer.put(responseMessageJString.getBytes());
	}
}
